package com.sale.goods.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ibm.icu.text.SimpleDateFormat;
import com.sale.common.core.constant.CacheNames;
import com.sale.common.core.domain.R;
import com.sale.common.core.exception.GlobalException;
import com.sale.common.core.utils.StringUtils;
import com.sale.common.mybatis.core.page.PageQuery;
import com.sale.common.mybatis.core.page.TableDataInfo;
import com.sale.common.redis.utils.CacheUtils;
import com.sale.common.satoken.utils.LoginHelper;
import com.sale.goods.domain.GoodsInvoiceInto;
import com.sale.goods.domain.GoodsMaterial;
import com.sale.goods.domain.dto.GoodsInvoiceIntoDto;
import com.sale.goods.domain.dto.GoodsMaterialDto;
import com.sale.goods.domain.dto.single.GoodsInvoiceIntoSingle;
import com.sale.goods.domain.vo.GoodsInvoiceIntoVo;
import com.sale.goods.mapper.GoodsInvoiceIntoMapper;
import com.sale.goods.mapper.GoodsMaterialMapper;
import com.sale.goods.service.IGoodsInvoiceIntoService;
import com.sale.order.api.RemoteSupplierService;
import com.sale.storage.api.RemotePurchaseReceiptService;
import com.sale.storage.api.vo.QuantityDataVo;
import com.sale.storage.api.vo.UpdateInvoicedQuantityVo;
import com.sale.system.api.RemoteMaterialService;
import com.sale.system.api.RemoteReviewService;
import com.sale.system.api.RemoteSubsidiary;
import com.sale.system.api.domain.SysDictData;
import com.sale.system.api.domain.SysMaterial;
import com.sale.system.api.domain.vo.SysAuditHistoryVo;
import lombok.RequiredArgsConstructor;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.ParseException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description 进项税发票实现类
 * @Date 23-07-19
 * @Author hl
 **/
@RequiredArgsConstructor
@Service
public class GoodsInvoiceIntoServiceImpl implements IGoodsInvoiceIntoService {

    private final GoodsInvoiceIntoMapper goodSInvoiceIntoMapper;

    private final GoodsMaterialMapper goodsMaterialMapper;

    @DubboReference
    private final RemoteReviewService remoteReviewService;

    @DubboReference
    private final RemoteMaterialService remoteMaterialService;

    @DubboReference
    private final RemoteSupplierService remoteSupplierService;

    @DubboReference
    private final RemoteSubsidiary remoteSubsidiary;

    @DubboReference
    private final RemotePurchaseReceiptService remotePurchaseReceiptService;

    /**
     * 分页查询进项税发票
     *
     * @param goodSInvoiceIntoVo 进项税发票,pageQuery 分页参数
     * @return TableDataInfo<GoodSInvoiceIntoDto>
     */
    @Override
    public TableDataInfo<GoodsInvoiceIntoDto> selectInvoiceIntoList(GoodsInvoiceIntoVo goodSInvoiceIntoVo, PageQuery pageQuery) throws ParseException {
        Page<GoodsInvoiceIntoDto> page = goodSInvoiceIntoMapper.selectInvoiceIntoList(pageQuery.build(), this.buildQueryWrapper(goodSInvoiceIntoVo));
        //渲染字典
        List<GoodsInvoiceIntoDto> list = page.getRecords();
        List<SysDictData> netArray = CacheUtils.get(CacheNames.SYS_DICT, "goods_invoice_type");
        Map<String, String> netMap = netArray.stream().collect(Collectors.toMap(SysDictData::getDictValue, SysDictData::getDictLabel));
        List<SysDictData> netArray3 = CacheUtils.get(CacheNames.SYS_DICT, "bill_state");
        Map<String, String> netMap3 = netArray3.stream().collect(Collectors.toMap(SysDictData::getDictValue, SysDictData::getDictLabel));
        //供应商
        Map<String,String> supplierMap= remoteSupplierService.getOpenSupplierFinance();
        //收支类别
        Map<String, String> map2 = remoteSubsidiary.selectDisburseList();
        for (GoodsInvoiceIntoDto dto:
        list) {
            //发票种类
            dto.setInvoiceSpeciesDict(netMap.get(dto.getInvoiceSpecies()));
            //收支类别
            dto.setInvoiceTypeDict(map2.get(dto.getInvoiceType()));
            //状态
            dto.setInvoiceStatusDict(netMap3.get(dto.getInvoiceStatus()));
            //供应商名称
            dto.setSupplierName(supplierMap.get(dto.getSupplierName()));
        }
        return TableDataInfo.build(page);
    }

    private Wrapper<GoodsInvoiceIntoVo> buildQueryWrapper(GoodsInvoiceIntoVo goodSInvoiceIntoVo) throws ParseException {
        SimpleDateFormat outputFormat = new SimpleDateFormat("yyyy-MM-dd");
        String formattedDate = "";
        String formattedDate2="";
        if(goodSInvoiceIntoVo.getBeginTime()!=null){
             formattedDate = outputFormat.format(outputFormat.parse(goodSInvoiceIntoVo.getBeginTime()));
        }
        if(goodSInvoiceIntoVo.getEndTime()!=null) {
             formattedDate2 = outputFormat.format(outputFormat.parse(goodSInvoiceIntoVo.getEndTime()));
        }
        String name = goodSInvoiceIntoVo.getSupplierName();
        if(StringUtils.isNotBlank(name)){
            String code = remoteSupplierService.getCodeBySupplierName(name);
            goodSInvoiceIntoVo.setSupplierName(code);
        }
        QueryWrapper<GoodsInvoiceIntoVo> wrapper = Wrappers.query();
        wrapper
            .like(ObjectUtil.isNotNull(goodSInvoiceIntoVo.getInvoiceNumber()), "t1.invoice_number", goodSInvoiceIntoVo.getInvoiceNumber())
            .like(StringUtils.isNotBlank(goodSInvoiceIntoVo.getInvoiceCode()), "t1.invoice_code", goodSInvoiceIntoVo.getInvoiceCode())
            .like(StringUtils.isNotBlank(goodSInvoiceIntoVo.getInvoiceSpecies()), "t1.invoice_species", goodSInvoiceIntoVo.getInvoiceSpecies())
            .eq(StringUtils.isNotBlank(goodSInvoiceIntoVo.getInvoiceType()), "t1.invoice_type", goodSInvoiceIntoVo.getInvoiceType())
            .eq(StringUtils.isNotBlank(goodSInvoiceIntoVo.getSupplierName()), "t1.supplier_name", goodSInvoiceIntoVo.getSupplierName())
            .eq(StringUtils.isNotBlank(goodSInvoiceIntoVo.getInvoiceStatus()), "t1.invoice_status", goodSInvoiceIntoVo.getInvoiceStatus()).between(goodSInvoiceIntoVo.getBeginTime() != null && goodSInvoiceIntoVo.getEndTime() != null,
                "t1.invoice_time",formattedDate,formattedDate2);
        return wrapper;
    }

    /**
     * 新增进项税发票
     *
     * @param goodSInvoiceIntoVo
     * @return int
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertInvoiceInto(GoodsInvoiceIntoVo goodSInvoiceIntoVo) throws Exception {
        String number = goodSInvoiceIntoVo.getInvoiceNumber();
        int count = goodSInvoiceIntoMapper.selectNumberCount(number);
        if(count>0){
            throw new GlobalException("该发票号码已存在!");
        }
        GoodsInvoiceInto into = new GoodsInvoiceInto();
        BeanUtils.copyProperties(goodSInvoiceIntoVo, into);
        into.setInvoiceStatus(1);
        List<GoodsMaterial> list = goodSInvoiceIntoVo.getMaterialRawList();
        Long intoId = IdWorker.getId();
        //合计金额
        BigDecimal b1 = new BigDecimal(0);
        //合计税额
        BigDecimal b2 = new BigDecimal(0);
        //新增物料明细
        for (GoodsMaterial goods :
            list) {
            goods.setGoodsId(IdWorker.getId());
            goods.setInvoiceId(intoId);
            b1 = b1.add(goods.getGoodsAmount());
            b2 = b2.add(goods.getGoodsTaxAmount());
        }
        //价税合计
        BigDecimal b3 = b1.add(b2);
        into.setTaxExclusive(b1);
        into.setTheExclusive(b2);
        into.setPriceTax(b3);
        into.setInvoiceIntoId(intoId);
        int os = goodSInvoiceIntoMapper.insert(into);
        goodsMaterialMapper.insertBatch(list);
        return os;
    }

    /**
     * 查询进项税发票
     *
     * @param invoiceIntoId
     * @return GoodSInvoiceIntoDto
     */
    @Override
    public GoodsInvoiceIntoSingle selectInvoiceIntoById(long invoiceIntoId) {
        GoodsInvoiceInto into = goodSInvoiceIntoMapper.selectById(invoiceIntoId);
        GoodsInvoiceIntoSingle single = new GoodsInvoiceIntoSingle();
        BeanUtils.copyProperties(into, single);
        //字典
        List<SysDictData> netArray = CacheUtils.get(CacheNames.SYS_DICT, "goods_invoice_type");
        Map<String, String> netMap = netArray.stream().collect(Collectors.toMap(SysDictData::getDictValue, SysDictData::getDictLabel));
        //发票种类

        single.setInvoiceSpeciesDict(netMap.get(single.getInvoiceSpecies()));
        //发票明细
        List<GoodsMaterialDto> goodsList = goodsMaterialMapper.selectByMaterial(invoiceIntoId);
        for (GoodsMaterialDto goods : goodsList) {
            SysMaterial sys = remoteMaterialService.selectMaterial(goods.getMaterialId());
            BeanUtils.copyProperties(sys, goods);
        }
        single.setMaterialRawList(goodsList);
        return single;
    }

    /**
     * 删除进项税发票
     *
     * @param invoiceIntoId
     * @return int
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteInvoiceIntoById(Long invoiceIntoId) {
        int os = goodSInvoiceIntoMapper.deleteById(invoiceIntoId);
        Map<String, Object> map = new HashMap<>();
        map.put("invoice_id", invoiceIntoId);
        List<GoodsMaterial> goodsList = goodsMaterialMapper.selectByMap(map);
        if (goodsList.size() > 0) {
            os = goodsMaterialMapper.deleteByMap(map);
        }
        return os;
    }

    /**
     * 修改进项税发票
     *
     * @param goodSInvoiceIntoVo
     * @return int
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateInvoiceIntoEdit(GoodsInvoiceIntoVo goodSInvoiceIntoVo) {
        if(goodSInvoiceIntoVo.getInvoiceStatus().equals("4")){
            SysAuditHistoryVo vo = new SysAuditHistoryVo();
            vo.setPerms("finance:inItemTax:review");
            vo.setAuditDoc(goodSInvoiceIntoVo.getInvoiceCode());
            int is = remoteReviewService.editHistory(vo);
            if (is == 0) {
                throw new GlobalException("修改失败,未找到审核历史!");
            }
        }
        GoodsInvoiceInto into = new GoodsInvoiceInto();
        BeanUtils.copyProperties(goodSInvoiceIntoVo, into);
        List<GoodsMaterial> list = goodSInvoiceIntoVo.getMaterialRawList();
        Long intoId = into.getInvoiceIntoId();
        Map<String, Object> map = new HashMap<>();
        map.put("invoice_id", intoId);
        goodsMaterialMapper.deleteByMap(map);
        //合计金额
        BigDecimal b1 = new BigDecimal(0);
        //合计税额
        BigDecimal b2 = new BigDecimal(0);
        //新增物料明细
        for (GoodsMaterial goods :
            list) {
            goods.setGoodsId(IdWorker.getId());
            goods.setInvoiceId(intoId);
            b1 = b1.add(goods.getGoodsAmount());
            b2 = b2.add(goods.getGoodsTaxAmount());
        }
        //价税合计
        BigDecimal b3 = b1.add(b2);
        into.setTaxExclusive(b1);
        into.setTheExclusive(b2);
        into.setPriceTax(b3);
        into.setInvoiceStatus(1);
        int os = goodSInvoiceIntoMapper.updateById(into);
        goodsMaterialMapper.insertBatch(list);
        return os;
    }

    /**
     * 提交进项税发票
     *
     * @param invoiceIntoId
     * @return int
     */
    @Override
    public int submitReview(Long invoiceIntoId) {
        GoodsInvoiceInto into = goodSInvoiceIntoMapper.selectById(invoiceIntoId);
        int status = into.getInvoiceStatus();
        if (status != 1) {
            throw new GlobalException("只有待提交状态才能提交审核");
        }
        GoodsInvoiceInto goods = new GoodsInvoiceInto();
        goods.setInvoiceIntoId(invoiceIntoId);
        goods.setInvoiceStatus(2);
        return goodSInvoiceIntoMapper.updateById(goods);
    }

    /**
     * 撤销进项税发票
     *
     * @param invoiceIntoId
     * @return int
     */
    @Override
    public int deleteReview(Long invoiceIntoId) {
        GoodsInvoiceInto goods = goodSInvoiceIntoMapper.selectById(invoiceIntoId);
        int status = goods.getInvoiceStatus();
        if (status != 2) {
            throw new GlobalException("只有待审核状态才能撤销审核");
        }
        GoodsInvoiceInto into = new GoodsInvoiceInto();
        into.setInvoiceIntoId(invoiceIntoId);
        into.setInvoiceStatus(1);
        return goodSInvoiceIntoMapper.updateById(into);
    }

    /**
     * 审核进项税发票
     *
     * @param goodSInvoiceIntoVo
     * @return int
     */
    @Override
    public int goodSExamineReview(GoodsInvoiceIntoVo goodSInvoiceIntoVo) throws Exception {
        SysAuditHistoryVo sysAuditHistoryVo = new SysAuditHistoryVo();
        Long id = goodSInvoiceIntoVo.getInvoiceIntoId();
        GoodsInvoiceInto into = goodSInvoiceIntoMapper.selectById(id);
        String perms = "finance:inItemTax:review";
        sysAuditHistoryVo.setPerms(perms);
        sysAuditHistoryVo.setModuleType(3);
        sysAuditHistoryVo.setAuditState(goodSInvoiceIntoVo.getAuditState());
        sysAuditHistoryVo.setAuditRemarks(goodSInvoiceIntoVo.getAuditOpinion());
        sysAuditHistoryVo.setAuditDoc(into.getInvoiceCode());
        sysAuditHistoryVo.setUserId(LoginHelper.getUserId());
        int data = remoteReviewService.getSequence(sysAuditHistoryVo);
        if (data == 0) {
            throw new GlobalException("未对该审核进行配置");
        }
        //1:通过，2：审核中，3：没权限 4:该人已经审核过
        GoodsInvoiceInto goods = new GoodsInvoiceInto();
        goods.setInvoiceIntoId(id);
        switch (data) {
            case 1:
                if(goodSInvoiceIntoVo.getAuditState()==2){
                    goods.setInvoiceStatus(4);
                }else{
                    goods.setInvoiceStatus(5);
                    UpdateInvoicedQuantityVo vo1 = new UpdateInvoicedQuantityVo();
                    List<QuantityDataVo> list2 = new ArrayList<>();
                    Map<String, Object> map = new HashMap<>();
                    map.put("invoice_id", id);
                    List<GoodsMaterial> list1 = goodsMaterialMapper.selectByMap(map);
                    list1.stream().map(x1 -> {
                        QuantityDataVo v1 = new QuantityDataVo();
                        v1.setReceiptNumber(x1.getReceiptNo());
                        v1.setQuantity(String.valueOf(x1.getGoodsNum()));
                        v1.setApprovedAmount(x1.getGoodsAmount());
                        v1.setDocumentType("采购入库");
                        return v1;
                    }).forEach(list2::add);
                    vo1.setList(list2);
                    remotePurchaseReceiptService.updateInvoicedQuantity(vo1);
                }
                break;
            case 2:
                goods.setInvoiceStatus(3);
                break;
            case 3:
                if (data == 0) {
                    throw new GlobalException("不具备审核权限");
                }
                break;
            case 4:
                if (data == 0) {
                    throw new GlobalException("请勿重复审核");
                }
                break;
        }
        //审核人
        goods.setExamineBy(LoginHelper.getUsername());
        //审核日期
        goods.setExamineTime(new Date());
        return goodSInvoiceIntoMapper.updateById(goods);
    }

    /**
     * 认证
     *
     * @param invoiceIntoId
     * @return int
     */
    @Override
    public int goodsThe(Long invoiceIntoId) {
        GoodsInvoiceInto into = goodSInvoiceIntoMapper.selectById(invoiceIntoId);
        int status = into.getInvoiceStatus();
        if (status != 5) {
            throw new GlobalException("只有待认证状态才能进行认证");
        }
        GoodsInvoiceInto goods = new GoodsInvoiceInto();
        goods.setInvoiceIntoId(invoiceIntoId);
        goods.setInvoiceStatus(6);
        return goodSInvoiceIntoMapper.updateById(goods);
    }


}
